// 封装 ajax
// 不是给浏览网页的人用的
// 给其他开发人员用的

/*
  步骤1: 验证各种参数是否符合数据格式
    1-1. options.url 参数的验证
      => 必填, 如果你没有传递 url 这一项, 那么不需要继续向后执行代码了
    1-2. options.method 参数的验证
      => 可以不填, 但是只要你填写了, 那么必须是 get 或者 post 字符串, 大小写无所谓
    1-3. options.async 参数的验证
      => 可以不填, 但是只要你填写了, 那么必须是 true 或者 false, 必须是一个 布尔值
    1-4. options.data 参数的验证
      => 可以不填, 但是只要你填写了, 那么必须是一个 字符串 类型
    1-5. options.token 参数的验证
      => 可以不填, 但是只要你填写了, 那么必须是一个 字符串 类型
    1-6. options.dataType 参数的验证
      => 可以不填, 但是只要你填写了, 那么必须是 'string' 或者 'json'
    1-7. options.success 参数的验证
      => 可以不填, 但是只要你填写了, 那么必须是一个 函数 数据类型
    1-8. options.error 参数的验证
      => 可以不填, 但是只要你填写了, 那么必须是一个 函数 数据类型
*/

/*
  步骤2: 准备一套默认值
    2-1. 按照我们设计好的默认值给出一个内容
    2-2. 对参数进行一个细微的调整
      => 当你是 GET 请求, 并且 data 有内容的时候
      => 我直接把 data 拼接在 url 的后面
*/

/*
  步骤3: 按照 _default 内的信息发送请求
*/
function ajax(options = {}) {
  // 给 options 设置一个默认值, 为 空对象
  // 如果你没有传递参数, 那么就是一个空对象

  // 提前从 options 里面先获取出来 method
  // 快速从对象内获取成员, 解构赋值
  const { url, method, async, data, token, dataType, success, error } = options

  // 1. 参数验证
  // 1-1. 验证 url
  if (!url) {
    // 代码能执行到这里, 说明 !options.url 是一个 true
    // 说明 options.url 是一个 false
    // 手动抛出异常, 手动报错
    // 语法: throw new Error('错误信息')
    throw new Error('url 为必填选项 ^_^ !')
  }

  // 1-2. 验证 method
  // 先把可以的写下来, 整体取反
  if (!(method === undefined || /^(get|post)$/i.test(method))) {
    // 代码能来到这里, 说明 method 既不是 undefined 也不是 get 也不是 post
    // 手动抛出异常
    throw new Error('目前只接受 GET 和 POST 请求方式, 请期待更新 O(∩_∩)O哈哈~ ')
  }

  // 1-3. 验证 async
  // 先把可以的写下来, 整体取反
  if (!(async === undefined || typeof async === 'boolean')) {
    // 代码能执行到这里, 说明 async 既不是 udnefined 也不是 布尔值
    throw new Error('async 需要传递一个 布尔值 (#^.^#)')
  }

  // 1-4. 验证 data
  if (!(data === undefined || typeof data === 'string')) {
    throw new Error('data 需要传递一个 字符串 类型')
  }

  // 1-5. 验证 token
  if (!(token === undefined || typeof token === 'string')) {
    throw new Error('token 需要传递一个 字符串 类型')
  }

  // 1-6. 验证 dataType
  if (!(dataType === undefined || /^(string|json)$/i.test(dataType))) {
    throw new Error('dataType 请传递一个 "string" 或者 "json"')
  }

  // 1-7. 验证 success
  if (!(success === undefined || typeof success === 'function')) {
    throw new Error('success 需要传递一个 函数数据 类型')
  }

  // 1-8. 验证 error
  if (!(error === undefined || typeof error === 'function')) {
    throw new Error('error 需要传递一个 函数数据 类型')
  }


  // 2. 准备一套默认值
  const _default = {
    // 2-1. 代码能执行到这里, url 肯定有
    url,
    // 2-2. method, 代码能来到这里, 说明 method 要么是 undefined, 要么是 get或者post
    method: method || 'GET',
    // 2-3. async, 代码能来到这里, 说明 async 要么是 undefined, 要么是 true 或者 false
    // async: typeof async === 'boolean' ? async : true
    async: async ?? true, // 空值运算
    // 2-4. data, 代码能来到这里, 说明 data 要么是 undefined, 要么是 字符串
    data: data || '',
    // 2-5. token, 代码能来到这里, 说明 token 要么是 undefined, 要么是 字符串
    token: token || '',
    // 2-6. dataType, 代码能来到这里, 说明 dataType 要么是 undefined, 要么是 'string', 要么是 'json'
    dataType: dataType || 'string',
    // success 代码能来到这里, 说明 success 要么是一个 undefined 要么是一个 函数
    success: success || function () {},
    error: error || function () {}
  }

  // 2-7. 判断你如果是 get 请求, 并且有参数, 直接给你拼接好
  if (/^get$/i.test(_default.method) && _default.data) {
    _default.url = _default.url + '?' + _default.data
  }

  // 3. 发送请求
  // 3-1. 准备 ajax 对象
  const xhr = new XMLHttpRequest()

  // 3-2. 配置请求信息
  xhr.open(_default.method, _default.url, _default.async)

  // 3-3. 接受响应
  xhr.onload = function () {
    // 暂时先打印一下响应体
    // 根据 _default 内的 dataType 来决定
    // 判断是否需要执行 JSON.parse()
    if (_default.dataType === 'string') {
      // 不需要执行 JSON.parse()
      _default.success(xhr.responseText)

      return
    }

    // 来到这里. 需要执行 JSON.parse 解析
    // 解析就有可能出错
    try {
      let result = JSON.parse(xhr.responseText)
      // 如果解析没有出错, 执行这里的代码
      _default.success(result)
    } catch (err) {
      // 如果解析出错了, 就会执行这里的代码
      _default.error(err, xhr.responseText)
    }
  }

  // 3-4. 设置请求头内的 token
  if (_default.token) xhr.setRequestHeader('authorization', _default.token)

  // 3-5. 判断如果是 post 请求, 设置 请求头的 content-type
  if (/^post$/i.test(_default.method)) {
    xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded')
    xhr.send(_default.data)
  } else {
    xhr.send()
  }
}
function setCookie(key, value, expires) {
  // 1. 判断 expires 是否传递的数据, 决定我如何操作
  // 如果没有传递, expires 是 undefined
  // 如果传递了, expires 就是一个 数字
  if (!expires) {
    // 代码能来到这里, 说明, 没有传递 expires
    // 直接设置 cookie
    document.cookie = key + '=' + value
    return
  }

  // 代码如果能执行到这里, 说明你要设置一个有过期时间的 cookie
  // 2. 根据传递进来的 expires 创建出一个时间对象
  const time = new Date()
  time.setTime(time.getTime() - 1000 * 60 * 60 * 8 + 1000 * expires)

  // 3. 根据调整好的 time 设置 cookie
  document.cookie = key + '=' + value + ';expires=' + time
}
